home *** CD-ROM | disk | FTP | other *** search
/ The CICA Windows Explosion! / The CICA Windows Explosion! - Disc 2.iso / programr / upc12bs1.zip / UUCP / uuxqt.c < prev   
C/C++ Source or Header  |  1993-10-03  |  51KB  |  1,482 lines

  1. /*
  2.       Program:    uuxqt.c              23 September 1991
  3.       Author:     Mitch Mitchell
  4.       Email:      mitch@harlie.lonestar.org
  5.  
  6.       This is a re-write of the (much cleaner) UUXQT.C originally
  7.       distributed with UUPC/Extended.  The modifications are
  8.       intended primarily to lay a foundation for support for the
  9.       more advanced features of UUX.
  10.  
  11.       Usage:      uuxqt -xDEBUG -sSYSTEM
  12. */
  13.  
  14. /*--------------------------------------------------------------------*/
  15. /*       Changes Copyright (c) 1989-1993 by Kendra Electronic         */
  16. /*       Wonderworks.                                                 */
  17. /*                                                                    */
  18. /*       All rights reserved except those explicitly granted by       */
  19. /*       the UUPC/extended license agreement.                         */
  20. /*--------------------------------------------------------------------*/
  21.  
  22. /*--------------------------------------------------------------------*/
  23. /*                          RCS Information                           */
  24. /*--------------------------------------------------------------------*/
  25.  
  26. /*
  27.  *    $Id: uuxqt.c 1.18 1993/10/03 22:10:24 ahd Exp $
  28.  *
  29.  *    Revision history:
  30.  *    $Log: uuxqt.c $
  31.  * Revision 1.18  1993/10/03  22:10:24  ahd
  32.  * Use signed for length of parameters
  33.  *
  34.  * Revision 1.17  1993/10/03  20:43:08  ahd
  35.  * Normalize comments to C++ double slash
  36.  *
  37.  * Revision 1.16  1993/09/29  23:29:56  ahd
  38.  * Add xqtrootdir for UUXQT
  39.  *
  40.  * Revision 1.15  1993/09/20  04:48:25  ahd
  41.  * TCP/IP support from Dave Watt
  42.  * 't' protocol support
  43.  * OS/2 2.x support (BC++ 1.0 for OS/2)
  44.  *
  45.  * Revision 1.14  1993/08/03  03:35:58  ahd
  46.  * Correct path pointer to initialized variable
  47.  *
  48.  * Revision 1.13  1993/08/03  03:11:49  ahd
  49.  * Initialize buffer for shell() in non-Windows environment
  50.  *
  51.  * Revision 1.12  1993/07/31  16:27:49  ahd
  52.  * Changes in support of Robert Denny's Windows support
  53.  *
  54.  * Revision 1.11  1993/07/24  03:40:55  ahd
  55.  * Agressively trap carriage returns at ends of lines (from X.* files
  56.  * being edited by elves with DOS editors!)
  57.  *
  58.  * Revision 1.10  1993/07/20  21:45:37  ahd
  59.  * Don't delete file after -2 abort from UUXQT
  60.  *
  61.  * Revision 1.9  1993/06/26  16:01:48  ahd
  62.  * Normalize white space used to parse strings
  63.  *
  64.  * Revision 1.8  1993/06/13  14:06:00  ahd
  65.  * Correct off-by-one error in RMAIL arg parse loop which crashed UUXQT
  66.  * on long system names
  67.  *
  68.  * Revision 1.7  1993/04/11  00:35:46  ahd
  69.  * Global edits for year, TEXT, etc.
  70.  *
  71.  * Revision 1.6  1993/04/05  04:35:40  ahd
  72.  * Use timestamp/file size information returned by directory search
  73.  *
  74.  * Revision 1.5  1992/11/25  12:59:17  ahd
  75.  * Change NUL to /dev/nul to prevent ImportPath() mangling.
  76.  *
  77.  * Revision 1.4  1992/11/23  03:56:06  ahd
  78.  * Selected fixes for use of generlized uux commands
  79.  *
  80.  * Revision 1.3  1992/11/19  03:03:33  ahd
  81.  * drop rcsid
  82.  */
  83.  
  84. /*--------------------------------------------------------------------*/
  85. /*                        System include files                        */
  86. /*--------------------------------------------------------------------*/
  87.  
  88. #include <stdio.h>
  89. #include <stdlib.h>
  90. #include <string.h>
  91. #include <ctype.h>
  92. #include <errno.h>
  93. #include <time.h>
  94. #include <fcntl.h>
  95. #include <process.h>
  96. #include <sys/types.h>
  97. #include <sys/stat.h>
  98. #include <io.h>
  99.  
  100. #ifdef _Windows
  101. #include <windows.h>
  102. #endif
  103.  
  104. /*--------------------------------------------------------------------*/
  105. /*                    UUPC/extended include files                     */
  106. /*--------------------------------------------------------------------*/
  107.  
  108. #include "lib.h"
  109. #include "arpadate.h"
  110. #include "dater.h"
  111. #include "expath.h"
  112. #include "getopt.h"
  113. #include "getseq.h"
  114. #include "hlib.h"
  115. #include "hostable.h"
  116. #include "import.h"
  117. #include "lock.h"
  118. #include "logger.h"
  119. #include "pushpop.h"
  120. #include "readnext.h"
  121. #include "security.h"
  122. #include "timestmp.h"
  123. #include "usertabl.h"
  124. #include "execute.h"
  125.  
  126. #ifdef _Windows
  127. #include "winutil.h"
  128. #endif
  129.  
  130. currentfile();
  131.  
  132. /*--------------------------------------------------------------------*/
  133. /*                      Execution flag defines                        */
  134. /*--------------------------------------------------------------------*/
  135.  
  136. typedef enum {
  137.         X_OUTPUT,     /* 'O' return output to "outnode"       */
  138.         X_FAILED,     /* 'Z' send status if command failed    */
  139.         X_SUCCESS,    /* 'n' send status if command succeeded */
  140.         X_INPUT,      /* 'B' return command input on error    */
  141.         X_USEEXEC,    /* 'E' process command using exec(2)    */
  142.         X_STATFIL,    /* 'M' return status to file on remote  */
  143.  
  144.         S_CORRUPT,
  145.         S_EMPTY,
  146.         S_NOREAD,
  147.         S_NOWRITE,
  148.         S_STDIN,
  149.  
  150.         E_NORMAL,
  151.         E_NOACC,
  152.         E_SIGNAL,
  153.         E_STATUS,
  154.         E_NOEXE,
  155.         E_FAILED,
  156.  
  157.         UU_LAST
  158.  
  159.         } UU_FLAGS;
  160.  
  161. /*--------------------------------------------------------------------*/
  162. /*                          Global Variables                          */
  163. /*--------------------------------------------------------------------*/
  164.  
  165. static char *spool_fmt = SPOOLFMT;
  166. static char *dataf_fmt = DATAFFMT;
  167. static char *send_cmd  = "S %s %s %s -%s %s 0666 %s\n";
  168.  
  169. /*--------------------------------------------------------------------*/
  170. /*                        Internal prototypes                         */
  171. /*--------------------------------------------------------------------*/
  172.  
  173. static void usage( void );
  174.  
  175. static boolean copylocal(const char *from, const char *to);
  176.  
  177. static boolean do_uuxqt( const char *sysname );
  178.  
  179. static void process( const char *fname,
  180.                      const char *remote,
  181.                      const char *executeDirectory);
  182.  
  183. char **create_environment(const char *logname,
  184.                           const char *requestor);
  185.  
  186. static void delete_environment( char **envp);
  187.  
  188. static boolean AppendData( const char *input, FILE* dataout);
  189.  
  190. static boolean do_copy( char *localfile,
  191.                        const char *rmtsystem,
  192.                        const char *remotefile,
  193.                        const char *requestor,
  194.                        const boolean success );
  195.  
  196. static void ReportResults(const int   status,
  197.                           const char *input,
  198.                                 char *output,
  199.                           const char *command,
  200.                           const char *job_id,
  201.                           const time_t jtime,
  202.                           const char *requestor,
  203.                           const char *outnode,
  204.                           const char *outname,
  205.                           const boolean xflag[],
  206.                           const char *statfil,
  207.                           const char *machine,
  208.                           const char *user);
  209.  
  210. static int shell(char *command,
  211.                  const char *inname,
  212.                  const char *outname,
  213.                  const char *remotename,
  214.                  boolean xflag[]);
  215.  
  216. static boolean MailStatus(char *tempfile,
  217.                           char *address,
  218.                           char *subject);
  219.  
  220. /*--------------------------------------------------------------------*/
  221. /*    m a i n                                                         */
  222. /*                                                                    */
  223. /*    Main program                                                    */
  224. /*--------------------------------------------------------------------*/
  225.  
  226. void main( int argc, char **argv)
  227. {
  228.    int c;
  229.    extern char *optarg;
  230.    extern int   optind;
  231.    char *sysname = "all";
  232.  
  233. /*--------------------------------------------------------------------*/
  234. /*     Report our version number and date/time compiled               */
  235. /*--------------------------------------------------------------------*/
  236.  
  237.    debuglevel = 1;
  238.    banner( argv );
  239.  
  240. #if defined(__CORE__)
  241.    copywrong = strdup(copyright);
  242.    checkref(copywrong);
  243. #endif
  244.  
  245. /*--------------------------------------------------------------------*/
  246. /*        Process our arguments                                       */
  247. /*--------------------------------------------------------------------*/
  248.  
  249.    while ((c = getopt(argc, argv, "s:x:")) !=  EOF)
  250.       switch(c) {
  251.  
  252.       case 's':
  253.          sysname = optarg;
  254.          break;
  255.  
  256.       case 'x':
  257.          debuglevel = atoi( optarg );
  258.          break;
  259.  
  260.       case '?':
  261.          usage();
  262.          exit(1);
  263.          break;
  264.  
  265.       default:
  266.          printmsg(0, "uuxqt - invalid option -%c", c);
  267.          usage();
  268.          exit(2);
  269.          break;
  270.    }
  271.  
  272.    if (optind != argc) {
  273.       fputs("Extra parameter(s) at end.\n", stderr);
  274.       usage();
  275.       exit(2);
  276.    }
  277.  
  278. /*--------------------------------------------------------------------*/
  279. /*                             Initialize                             */
  280. /*--------------------------------------------------------------------*/
  281.  
  282.    tzset();                      // Set up time zone information
  283.  
  284.    if (!configure( B_UUXQT ))
  285.       exit(1);   /* system configuration failed */
  286.  
  287. /*--------------------------------------------------------------------*/
  288. /*                  Switch to the spooling directory                  */
  289. /*--------------------------------------------------------------------*/
  290.  
  291.    PushDir( E_spooldir );
  292.    atexit( PopDir );
  293.  
  294. /*--------------------------------------------------------------------*/
  295. /*                     Initialize logging file                        */
  296. /*--------------------------------------------------------------------*/
  297.  
  298.    openlog( NULL );
  299.  
  300.    checkuser( E_mailbox  );   // Force User Table to initialize
  301.    checkreal( E_mailserv );   // Force Host Table to initialize
  302.  
  303.    if (!LoadSecurity())
  304.    {
  305.       printmsg(0,"Unable to initialize security, see previous message");
  306.       exit(2);
  307.    } /* if (!LoadSecurity()) */
  308.  
  309. #if defined(_Windows)
  310.    atexit( CloseEasyWin );               // Auto-close EasyWin on exit
  311. #endif
  312.  
  313. /*--------------------------------------------------------------------*/
  314. /*                Set up search path for our programs                 */
  315. /*--------------------------------------------------------------------*/
  316.  
  317.    if ( E_uuxqtpath != NULL )
  318.    {
  319.       char buf[BUFSIZ];
  320.       char *p;
  321.       sprintf(buf,"PATH=%s", E_uuxqtpath);
  322.       p = newstr(buf);
  323.  
  324.       if (putenv( p ))
  325.       {
  326.          printmsg(0,"Unable to set path \"%s\"", p);
  327.          panic();
  328.       } /* if (putenv( p )) */
  329.  
  330.    } /* if ( E_uuxqtpath != NULL ) */
  331.  
  332. /*--------------------------------------------------------------------*/
  333. /*              Disable OS/2 undelete support if desired              */
  334. /*--------------------------------------------------------------------*/
  335.  
  336.    if ( !bflag[ F_UNDELETE ] )
  337.       putenv( "DELDIR=");
  338.  
  339. /*--------------------------------------------------------------------*/
  340. /*    Actually invoke the processing routine for the eXecute files    */
  341. /*--------------------------------------------------------------------*/
  342.  
  343.    do_uuxqt( sysname );
  344.    if( equal( sysname , "all" ) )
  345.        do_uuxqt( E_nodename );
  346.  
  347.    exit(0);
  348.  
  349. } /* main */
  350.  
  351. /*--------------------------------------------------------------------*/
  352. /*    d o _ u u x q t                                                 */
  353. /*                                                                    */
  354. /*    Processing incoming eXecute (X.*) files for a remote system     */
  355. /*--------------------------------------------------------------------*/
  356.  
  357. static boolean do_uuxqt( const char *sysname )
  358. {
  359.    struct HostTable *hostp;
  360.    static char uu_machine[] = UU_MACHINE "=";
  361.    char hostenv[sizeof uu_machine + 25 + 2];
  362.    char executeDirectory[FILENAME_MAX];
  363.    char *pattern;
  364.  
  365. /*--------------------------------------------------------------------*/
  366. /*                 Determine if we have a valid host                  */
  367. /*--------------------------------------------------------------------*/
  368.  
  369.    if( !equal( sysname , "all" ) ) {
  370.       if (equal( sysname , E_nodename ))
  371.           hostp = checkname( sysname );
  372.       else
  373.           hostp = checkreal( sysname );
  374.  
  375.       if (hostp  ==  BADHOST) {
  376.          printmsg(0, "Unknown host \"%s\".", sysname );
  377.          exit(1);
  378.       }
  379.  
  380.    } else
  381.         hostp = nexthost( TRUE );
  382.  
  383. /*--------------------------------------------------------------------*/
  384. /*                Define mask for execution directory                 */
  385. /*--------------------------------------------------------------------*/
  386.  
  387.    if (( E_xqtRootDir == NULL ) || equali( E_xqtRootDir, E_spooldir ))
  388.       sprintf( executeDirectory, "%s/%%s/XQT", E_spooldir );
  389.                                  // Nice parallel construction
  390.    else
  391.       sprintf( executeDirectory, "%s/XQT/%%s", E_xqtRootDir);
  392.                                  // Fewer directories than if we
  393.                                  // use the spool version
  394.  
  395.    pattern = newstr( executeDirectory );  // Save pattern for posterity
  396.  
  397. /*--------------------------------------------------------------------*/
  398. /*             Outer loop for processing different hosts              */
  399. /*--------------------------------------------------------------------*/
  400.  
  401.    while  (hostp != BADHOST)
  402.    {
  403.       char fname[FILENAME_MAX];
  404.       boolean locked = FALSE;
  405.  
  406. /*--------------------------------------------------------------------*/
  407. /*                Initialize security for this remote                 */
  408. /*--------------------------------------------------------------------*/
  409.  
  410.       if ( !equal(sysname, E_nodename) &&
  411.            (securep = GetSecurity( hostp )) == NULL )
  412.          printmsg(0,"No security defined for \"%s\","
  413.                   " cannot process X.* files",
  414.                   hostp->hostname );
  415.       else {
  416.  
  417. /*--------------------------------------------------------------------*/
  418. /*              Set up environment for the machine name               */
  419. /*--------------------------------------------------------------------*/
  420.  
  421.          sprintf(hostenv,"%s%.25s", uu_machine, hostp->hostname);
  422.  
  423.          if (putenv( hostenv ))
  424.          {
  425.             printmsg(0,"Unable to set environment \"%s\"",hostenv);
  426.             panic();
  427.          }
  428.  
  429.          sprintf(executeDirectory , pattern, hostp->hostname );
  430.          printmsg(5,"Execute directory is %s", executeDirectory );
  431.  
  432. /*--------------------------------------------------------------------*/
  433. /*           Inner loop for processing files from one host            */
  434. /*--------------------------------------------------------------------*/
  435.  
  436.          while (readnext(fname, hostp->hostname, "X", NULL, NULL, NULL) )
  437.          {
  438.             if ( locked || LockSystem( hostp->hostname , B_UUXQT ))
  439.             {
  440.                process( fname , hostp->hostname, executeDirectory );
  441.                locked = TRUE;
  442.             }
  443.             else
  444.                break;               // We didn't get the lock
  445.  
  446.          } /* while */
  447.  
  448.          if ( locked )
  449.             UnlockSystem();
  450.  
  451.       } /* else if */
  452.  
  453. /*--------------------------------------------------------------------*/
  454. /*                        Restore environment                         */
  455. /*--------------------------------------------------------------------*/
  456.  
  457.       putenv( uu_machine );   // Reset to empty string
  458.  
  459. /*--------------------------------------------------------------------*/
  460. /*    If processing all hosts, step to the next host in the queue     */
  461. /*--------------------------------------------------------------------*/
  462.  
  463.       if( equal(sysname,"all") )
  464.          hostp = nexthost( FALSE );
  465.       else
  466.          hostp = BADHOST;
  467.  
  468.    } /*while nexthost*/
  469.  
  470.    return FALSE;
  471.  
  472. } /* do_uuxqt */
  473.  
  474. /*--------------------------------------------------------------------*/
  475. /*    p r o c e s s                                                   */
  476. /*                                                                    */
  477. /*    Process a single execute file                                   */
  478. /*--------------------------------------------------------------------*/
  479.  
  480. static void process( const char *fname,
  481.                      const char *remote,
  482.                      const char *executeDirectory)
  483. {
  484.    char *command = NULL,
  485.         *input = NULL,
  486.         *output = NULL,
  487.         *job_id = NULL,
  488.         *token = NULL,
  489.         line[BUFSIZ];
  490.    char hostfile[FILENAME_MAX];
  491.    boolean skip = FALSE;
  492.    boolean reject = FALSE;
  493.    FILE *fxqt;
  494.    int   status;
  495.  
  496.    char *outnode = NULL;
  497.    char *outname = NULL;
  498.    char *user = NULL;
  499.    char *requestor = NULL;
  500.    char *statfil = NULL;
  501.    char *machine = NULL;
  502.    char **envp;
  503.  
  504.    boolean xflag[UU_LAST - 1] = { 0 };
  505.    time_t jtime = time(NULL);
  506.  
  507. /*--------------------------------------------------------------------*/
  508. /*                         Open the X.* file                          */
  509. /*--------------------------------------------------------------------*/
  510.  
  511.    if ( (fxqt = FOPEN(fname, "r", BINARY_MODE)) == NULL)
  512.    {
  513.       printerr(fname);
  514.       return;
  515.    }
  516.    else
  517.       printmsg(2, "processing %s", fname);
  518.  
  519. /*--------------------------------------------------------------------*/
  520. /*                  Begin loop to read the X.* file                   */
  521. /*--------------------------------------------------------------------*/
  522.  
  523.    while (!skip & (fgets(line, BUFSIZ, fxqt) != NULL))
  524.    {
  525.       char *cp;
  526.  
  527.       if ( (cp = strchr(line, '\n')) != NULL )
  528.          *cp = '\0';
  529.  
  530.       printmsg(5, "Input read: %s", line);
  531.  
  532. /*--------------------------------------------------------------------*/
  533. /*            Process the input line according to its type            */
  534. /*--------------------------------------------------------------------*/
  535.  
  536.       switch (line[0])
  537.       {
  538.  
  539.       case '#':
  540.          break;
  541.  
  542. /*--------------------------------------------------------------------*/
  543. /*                  User which submitted the command                  */
  544. /*--------------------------------------------------------------------*/
  545.  
  546.       case 'U':
  547.          if ( (cp = strtok(line + 1,WHITESPACE)) == NULL )
  548.          {
  549.             printmsg(0,"No user on U line in file \"%s\"", fname );
  550.             reject = TRUE;
  551.             break;
  552.          }
  553.          else {
  554.              user = strdup(cp);
  555.              checkref(user);
  556.          };
  557.                                     // Get the system name
  558.          if ( (cp = strtok(NULL,WHITESPACE)) == NULL)
  559.          {                          // Did we get a string?
  560.             printmsg(2,"No node on U line in file \"%s\"", fname );
  561.             cp = (char *) remote;
  562.          }
  563.          else if (!equal(cp,remote))
  564.          {
  565.             printmsg(2,"Node on U line in file \"%s\" doesn't match remote",
  566.                      fname );
  567.             cp = (char * ) remote;
  568.          };
  569.          machine = newstr(cp);
  570.          break;
  571.  
  572. /*--------------------------------------------------------------------*/
  573. /*                       Input file for command                       */
  574. /*--------------------------------------------------------------------*/
  575.  
  576.       case 'I':
  577.          cp = strtok( line + 1, WHITESPACE );
  578.          if ( cp == NULL )
  579.          {
  580.             printmsg(0,"No input file name on I line");
  581.             reject = TRUE;
  582.          }
  583.          else {
  584.             input = strdup( cp );
  585.             checkref(input);
  586.             if (!equal(remote, E_nodename) &&
  587.                 !(equaln(input,"D.",2) || ValidateFile( input, ALLOW_READ)))
  588.             {
  589.                 reject = TRUE;
  590.                 xflag[S_NOREAD] = TRUE;
  591.             }
  592.          } /* else */
  593.          break;
  594.  
  595. /*--------------------------------------------------------------------*/
  596. /*                      Output file for command                       */
  597. /*--------------------------------------------------------------------*/
  598.  
  599.       case 'O':
  600.          if ( (cp = strtok(line + 1, WHITESPACE)) != NULL )
  601.          {
  602.              outname = strdup(cp);
  603.              checkref(outname);
  604.              xflag[X_OUTPUT] = TRUE;  // return output to "outnode"
  605.  
  606.              if ( (cp = strtok(NULL,WHITESPACE)) != NULL)
  607.              {                // Did we get a string?
  608.                    outnode = strdup(cp);
  609.                    checkref(outnode);
  610.                    checkreal(outnode);
  611.              }
  612.              else if (!equal(remote, E_nodename))
  613.              {
  614.                 if (!(equaln(outname,"D.",2) || ValidateFile( outname, ALLOW_WRITE)))
  615.                 {
  616.                     reject = TRUE;
  617.                     xflag[S_NOWRITE] = TRUE;
  618.                 } /* if */
  619.              } /* else if (!equal(remote, E_nodename)) */
  620.          } /* if ( (cp = strtok(NULL,WHITESPACE)) != NULL ) */
  621.          break;
  622.  
  623. /*--------------------------------------------------------------------*/
  624. /*                         Command to execute                         */
  625. /*--------------------------------------------------------------------*/
  626.  
  627.       case 'C':
  628.          cp = strtok( line + 2, "\r\n" );
  629.          if ( cp == NULL )
  630.          {
  631.             printmsg(0,"No command name on C line");
  632.             reject = TRUE;
  633.          }
  634.          else {
  635.             command = strdup( cp );
  636.             checkref(command);
  637.          }
  638.          break;
  639.  
  640. /*--------------------------------------------------------------------*/
  641. /*                      Job Id for status reporting                   */
  642. /*--------------------------------------------------------------------*/
  643.  
  644.       case 'J':
  645.          if ( (cp = strtok(line + 1, WHITESPACE)) == NULL )
  646.          {
  647.             printmsg(0,"No job id on J line in file \"%s\"", fname );
  648.             reject = TRUE;
  649.          }
  650.          else {
  651.             job_id = strdup( cp );
  652.             checkref( job_id );
  653.          } /* else */
  654.          break;
  655.  
  656. /*--------------------------------------------------------------------*/
  657. /*                 Check that a required file exists                  */
  658. /*--------------------------------------------------------------------*/
  659.  
  660.       case 'F':
  661.          token = strtok(line + 1, WHITESPACE);
  662.          importpath(hostfile, token, remote);
  663.  
  664.          if ( access( hostfile, 0 ))   // Does the host file exist?
  665.          {                             // No --> Skip the file
  666.             printmsg(0,"Missing file %s (%s) for %s, command skipped",
  667.                      token, hostfile, fname);
  668.             skip = TRUE;
  669.          }
  670.          break;
  671.  
  672. /*--------------------------------------------------------------------*/
  673. /*             Requestor name (overrides user name, above)            */
  674. /*--------------------------------------------------------------------*/
  675.  
  676.       case 'R':
  677.          if ( (cp = strtok(line + 1,WHITESPACE)) == NULL )
  678.          {
  679.             printmsg(0,"No requestor on R line in file \"%s\"", fname );
  680.             reject = TRUE;
  681.          }
  682.          else {
  683.             requestor = strdup(cp);
  684.             checkref(requestor);
  685.          }
  686.          break;
  687.  
  688. /*--------------------------------------------------------------------*/
  689. /*        Status file name to return info to on remote node           */
  690. /*--------------------------------------------------------------------*/
  691.  
  692.       case 'M':
  693.          if ( (cp = strtok(line + 1, WHITESPACE)) == NULL )
  694.             printmsg(0,"No file name on M line in file \"%s\"", fname);
  695.          else {
  696.             statfil = strdup(cp);
  697.             checkref(statfil);
  698.             xflag[X_STATFIL] = TRUE;     // return status to remote file
  699.          }
  700.          break;
  701.  
  702. /*--------------------------------------------------------------------*/
  703. /*                            Flag fields                             */
  704. /*--------------------------------------------------------------------*/
  705.  
  706.       case 'Z': xflag[X_FAILED] = TRUE;   // send status if command failed
  707.          break;
  708.  
  709.       case 'N': xflag[X_FAILED] = FALSE;  // send NO status if command failed
  710.          break;
  711.  
  712.       case 'n': xflag[X_SUCCESS] = TRUE;  // send status if command succeeded
  713.          break;
  714.  
  715.       case 'z': xflag[X_SUCCESS] = FALSE; // NO status if command succeeded
  716.          break;
  717.  
  718.       case 'B': xflag[X_INPUT] = TRUE;    // return command input on error
  719.          break;
  720.  
  721.       case 'e': xflag[X_USEEXEC] = FALSE; // process command using sh(1)
  722.          break;
  723.  
  724.       case 'E': xflag[X_USEEXEC] = TRUE;  // process command using exec(2)
  725.          break;
  726.  
  727. /*--------------------------------------------------------------------*/
  728. /*                    Quietly ignore unknown fields                   */
  729. /*--------------------------------------------------------------------*/
  730.  
  731.       default :
  732.          break;
  733.  
  734.       } /* switch */
  735.    } /* while (!skip & (fgets(line, BUFSIZ, fxqt) != NULL)) */
  736.  
  737.    if ( fxqt != NULL )
  738.       fclose(fxqt);
  739.  
  740.  
  741.    if ((command == NULL) && !skip)
  742.    {
  743.       printmsg(0,"No command supplied for X.* file %s, skipped", fname);
  744.       reject = TRUE;
  745.    }
  746.  
  747. /*--------------------------------------------------------------------*/
  748. /*           We have the data for this command; process it            */
  749. /*--------------------------------------------------------------------*/
  750.  
  751.    if ( ! (skip || reject ))
  752.    {
  753.       if ( user == NULL )
  754.       {
  755.          user = strdup("uucp");    // User if none given
  756.          checkref(user);
  757.       }
  758.  
  759.       if (requestor == NULL)
  760.       {
  761.          requestor = strdup(user);
  762.          checkref(requestor);
  763.       }
  764.  
  765.       if (input == NULL)
  766.          input = strdup("/dev/nul");
  767.  
  768.       if (output == NULL)
  769.          output = mktempname(NULL, "OUT");
  770.  
  771.       printmsg(equaln(command,RMAIL,5) ? 2 : 0,
  772.                "uuxqt: executing \"%s\" for user \"%s\" at  \"%s\"",
  773.                    command, user, machine);
  774.  
  775. /*--------------------------------------------------------------------*/
  776. /*             Create the environment and run the command             */
  777. /*--------------------------------------------------------------------*/
  778.  
  779.       envp = create_environment("uucp", requestor);
  780.       status = shell(command, input, output, remote, xflag );
  781.       delete_environment(envp);
  782.  
  783.       ReportResults( status, input, output, command, job_id,
  784.                      jtime, requestor, outnode, outname, xflag,
  785.                      statfil, machine, user);
  786.  
  787. /*--------------------------------------------------------------------*/
  788. /*                  Clean up files after the command                  */
  789. /*--------------------------------------------------------------------*/
  790.  
  791.       if ( status > -2 )
  792.       {
  793.          unlink(fname);       // Already a local file name
  794.  
  795.          if (equaln(input,"D.",2))
  796.          {
  797.              importpath(hostfile, input, remote);
  798.              unlink(hostfile);
  799.          }
  800.  
  801.          if (xflag[X_OUTPUT])
  802.          {
  803.              importpath(hostfile, output, remote);
  804.              unlink(hostfile);
  805.          }
  806.  
  807.       } /* if ( status > -2 ) */
  808.  
  809.    }
  810.    else if (reject && !skip)
  811.         unlink(fname);       // Already a local file name
  812.  
  813. /*--------------------------------------------------------------------*/
  814. /*              Free various temporary character strings              */
  815. /*--------------------------------------------------------------------*/
  816.  
  817.    if (command    != NULL) free(command);
  818.    if (input      != NULL) free(input);
  819.    if (job_id     != NULL) free(job_id);
  820.    if (outnode    != NULL) free(outnode);
  821.    if (output     != NULL) free(output);
  822.    if (requestor  != NULL) free(requestor);
  823.    if (statfil    != NULL) free(statfil);
  824.    if (user       != NULL) free(user);
  825.  
  826. } /* process */
  827.  
  828. /*--------------------------------------------------------------------*/
  829. /*    s h e l l                                                       */
  830. /*                                                                    */
  831. /*    Simulate a Unix command                                         */
  832. /*--------------------------------------------------------------------*/
  833.  
  834. static int shell(char *command,
  835.                  const char *inname,
  836.                  const char *outname,
  837.                  const char *remotename,
  838.                  boolean xflag[])
  839. {
  840.    int    result = 0;
  841.    char   inlocal[FILENAME_MAX];
  842.    char   outlocal[FILENAME_MAX];
  843.    char   buf[255];
  844.  
  845.    char   *cmdname;
  846.    char   *parameters;
  847.  
  848.    if (xflag[X_USEEXEC])
  849.       printmsg(2, "exec(2) not supported, executing using spawn");
  850.  
  851. /*--------------------------------------------------------------------*/
  852. /*         Determine the command name and parameters, if any          */
  853. /*--------------------------------------------------------------------*/
  854.  
  855.    cmdname = strtok( command, WHITESPACE );
  856.    parameters = strtok( NULL, "\r\n" );
  857.  
  858.    if ( parameters != NULL )
  859.    {
  860.       while (isspace( *parameters ) || iscntrl( *parameters ))
  861.          parameters++;
  862.  
  863.       if ( !strlen( parameters ))
  864.          parameters = NULL;
  865.  
  866.    } /* if ( parameters != NULL ) */
  867.  
  868. /*--------------------------------------------------------------------*/
  869. /*    Verify we support the command, and get it's real name, if so    */
  870. /*--------------------------------------------------------------------*/
  871.  
  872.    if ( (!equal(remotename, E_nodename)) && (!ValidateCommand( cmdname )) )
  873.    {
  874.       printmsg(0,"Command \"%s\" not allowed at this site", cmdname);
  875.       xflag[E_NOEXE] = TRUE;
  876.       return 99;
  877.    }
  878.  
  879. /*--------------------------------------------------------------------*/
  880. /*                     Open files for processing                      */
  881. /*--------------------------------------------------------------------*/
  882.  
  883.    if (inname != NULL)
  884.       importpath(inlocal, inname, remotename);
  885.  
  886.    if ( outname != NULL )
  887.       importpath(outlocal, outname, remotename);
  888.  
  889. /*--------------------------------------------------------------------*/
  890. /*               We support the command; execute it                   */
  891. /*--------------------------------------------------------------------*/
  892.  
  893.    fflush(logfile);
  894.  
  895. /*--------------------------------------------------------------------*/
  896. /*               RNEWS may be special, handle it if so                */
  897. /*--------------------------------------------------------------------*/
  898.  
  899.    if (equal(cmdname,RNEWS) &&
  900.        bflag[F_WINDOWS] &&
  901.        ( inname != NULL ))       // rnews w/input?
  902.    {
  903.       strcpy( buf, "-f " );
  904.       strcat( buf, inlocal );
  905.       parameters = buf;          // We explicitly ignore all parameters
  906.                                  // on the RNEWS command
  907.  
  908.       result = execute( RNEWS,
  909.                         buf,
  910.                         NULL,
  911.                         outname == NULL ? NULL : outlocal,
  912.                         TRUE,
  913.                         FALSE );
  914.    }
  915.  
  916. /*--------------------------------------------------------------------*/
  917. /*        RMAIL is special, we need to break up the parameters        */
  918. /*--------------------------------------------------------------------*/
  919.  
  920.    else if (equal(cmdname,RMAIL) && ( inname != NULL )) // rmail w/input?
  921.    {
  922.       parameters = strtok( parameters, WHITESPACE );
  923.  
  924.       while (( parameters != NULL ) && (result != -1 ))
  925.       {
  926.  
  927.          boolean firstPass = TRUE;
  928.          int left = 0;
  929.  
  930. #if defined(__OS2__) || defined(WIN32)
  931.          int rlen =  254 ;
  932. #elif defined(__TURBOC__)
  933.          int rlen =  126 ;
  934. #else
  935.          int rlen = (_osmode == DOS_MODE) ? 126 :  254;
  936. #endif
  937.  
  938. #ifdef _Windows
  939.          if ( bflag[F_WINDOWS] )
  940.          {
  941.             strcpy( buf, "-f ");
  942.             strcat( buf, inlocal);
  943.             strcat( buf, " ");
  944.          }
  945.          else
  946.             *buf = '\0';
  947. #else
  948.          *buf = '\0';
  949. #endif
  950.          rlen -= strlen( buf ) + strlen( RMAIL ) + 1;
  951.  
  952. /*--------------------------------------------------------------------*/
  953. /*                   Copy addresses into the buffer                   */
  954. /*--------------------------------------------------------------------*/
  955.  
  956.          left = rlen - strlen( parameters );
  957.  
  958.          while ((parameters != NULL) && (left > 0))
  959.          {
  960.             char *next = strtok( NULL, "");
  961.  
  962.             if ( *parameters == '-')   // Option flag for mail?
  963.                printmsg(0,"Disallowed option %s ignored",parameters);
  964.             else {                     // Not option, add to param list
  965.                strcat( buf, " ");
  966.                strcat( buf, parameters );
  967.                rlen -= strlen( parameters ) + 1;
  968.                firstPass = FALSE;
  969.             }
  970.  
  971. /*--------------------------------------------------------------------*/
  972. /*                       Step to next parameter                       */
  973. /*--------------------------------------------------------------------*/
  974.  
  975.             if ( next == NULL )
  976.                parameters = NULL;
  977.             else
  978.                parameters = strtok( next, WHITESPACE );
  979.  
  980.          } /* while ( parameters != NULL ) */
  981.  
  982.          if (firstPass)       // Did we process at least one addr?
  983.          {                    // No --> Serious problem!
  984.             printmsg(0,
  985.                      "Address \"%s\" too long (%d chars)!  %d available, short fall would be %d",
  986.                       parameters,
  987.                       strlen(parameters),
  988.                       rlen,
  989.                       left );
  990.  
  991.             panic();
  992.          } /* if (*buf = '\0') */
  993.  
  994.       } /* while */
  995.  
  996. /*--------------------------------------------------------------------*/
  997. /*               Execute one command line of addresses                */
  998. /*--------------------------------------------------------------------*/
  999.  
  1000.       result = execute( RMAIL,
  1001.                         buf,
  1002.                         bflag[F_WINDOWS] ? NULL : inlocal,
  1003.                         outname == NULL ? NULL : outlocal,
  1004.                         TRUE,
  1005.                         FALSE );
  1006.  
  1007.       if ( result != 0 )    // Did command execution fail?
  1008.       {
  1009.          printmsg(0,"shell: command \"%s %s\" returned error code %d",
  1010.                cmdname, buf, result);
  1011.          panic();
  1012.       }
  1013.  
  1014.    } /* if (equal(cmdname,RMAIL) && ( inname != NULL )) */
  1015.    else
  1016.       result = execute( command,
  1017.                         parameters,
  1018.                         inlocal,
  1019.                         outlocal,
  1020.                         TRUE,
  1021.                         FALSE );
  1022.  
  1023. /*--------------------------------------------------------------------*/
  1024. /*                    Determine result of command                     */
  1025. /*--------------------------------------------------------------------*/
  1026.  
  1027.    if ( result == 0 )
  1028.       xflag[E_NORMAL] = TRUE;
  1029.    else if ( result > 0 )
  1030.       xflag[E_STATUS] = TRUE;
  1031.  
  1032.    fflush(logfile);
  1033.  
  1034.    return result;
  1035.  
  1036. } /* shell */
  1037.  
  1038. /*--------------------------------------------------------------------*/
  1039. /*    u s a g e                                                       */
  1040. /*                                                                    */
  1041. /*    Report how to run this program                                  */
  1042. /*--------------------------------------------------------------------*/
  1043.  
  1044. static void usage( void )
  1045. {
  1046.    fputs("Usage:\tuuxqt\t[-xDEBUG] [-sSYSTEM]", stderr);
  1047.    exit(1);
  1048. } /* usage */
  1049.  
  1050. /*--------------------------------------------------------------------*/
  1051. /*    c o p y l o c a l                                               */
  1052. /*                                                                    */
  1053. /*    Copy Local Files                                                */
  1054. /*--------------------------------------------------------------------*/
  1055.  
  1056. static boolean copylocal(const char *from, const char *to)
  1057. {
  1058.       int  fd_from, fd_to;
  1059.       int  nr;
  1060.       int  nw = -1;
  1061.       char buf[BUFSIZ];            // faster if we alloc a big buffer
  1062.  
  1063.       /* This would be even faster if we determined that both files
  1064.          were on the same device, dos >= 3.0, and used the dos move
  1065.          function */
  1066.  
  1067.       if ((fd_from = open(from, O_RDONLY | O_BINARY)) == -1)
  1068.          return FALSE;        // failed
  1069.  
  1070.       /* what if the to is a directory? */
  1071.       /* possible with local source & dest uucp */
  1072.  
  1073.       if ((fd_to = open(to, O_CREAT | O_BINARY | O_WRONLY, S_IWRITE | S_IREAD)) == -1) {
  1074.          close(fd_from);
  1075.          return FALSE;        // failed
  1076.          /* NOTE - this assumes all the required directories exist!  */
  1077.       }
  1078.  
  1079.       while  ((nr = read(fd_from, buf, sizeof buf)) > 0 &&
  1080.          (nw = write(fd_to, buf, nr)) == nr)
  1081.          ;
  1082.  
  1083.       close(fd_to);
  1084.       close(fd_from);
  1085.  
  1086.       if (nr != 0 || nw == -1)
  1087.          return FALSE;        // failed in copy
  1088.       return TRUE;
  1089. } /* copylocal */
  1090.  
  1091. /*--------------------------------------------------------------------*/
  1092. /*    c r e a t e _ e n v i r o n m e n t                             */
  1093. /*                                                                    */
  1094. /*    Create the environment array for subprocesses                   */
  1095. /*--------------------------------------------------------------------*/
  1096.  
  1097. char **create_environment(const char *logname,
  1098.                           const char *requestor)
  1099. {
  1100.    char buffer[MAXADDR + 20];
  1101.    int subscript = 0;
  1102.    char **envp = (char **) malloc(sizeof(char *) * 3);
  1103.  
  1104.    checkref(envp);
  1105.  
  1106. /*--------------------------------------------------------------------*/
  1107. /*              "Current" user id processing the request              */
  1108. /*--------------------------------------------------------------------*/
  1109.  
  1110.    if ( logname != NULL )
  1111.    {
  1112.      sprintf(buffer,"%s=%s", LOGNAME, logname);
  1113.      envp[subscript] = strdup(buffer);
  1114.      checkref(envp[subscript++]);
  1115.    }
  1116.  
  1117. /*--------------------------------------------------------------------*/
  1118. /*               user id/nodename of original requestor               */
  1119. /*--------------------------------------------------------------------*/
  1120.  
  1121.    if ( requestor != NULL )
  1122.    {
  1123.       sprintf(buffer,"%s=%s",UU_USER, requestor);
  1124.       envp[subscript] =  strdup(buffer);
  1125.       checkref(envp[subscript++]);
  1126.    }
  1127.  
  1128.    envp[subscript] =  NULL;   // Terminate the list
  1129.  
  1130. /*--------------------------------------------------------------------*/
  1131. /*               Now put the data into our environment                */
  1132. /*--------------------------------------------------------------------*/
  1133.  
  1134.    while( subscript-- > 0)
  1135.    {
  1136.       if (putenv( envp[subscript] ))
  1137.       {
  1138.          printmsg(0,"Unable to set environment \"%s\"",envp[subscript]);
  1139.          panic();
  1140.       }
  1141.    } /* while */
  1142.  
  1143.    return envp;
  1144. } /* create_environment */
  1145.  
  1146. /*--------------------------------------------------------------------*/
  1147. /*    d e l e t e  _ e n v i r o n m e n t                            */
  1148. /*                                                                    */
  1149. /*    Delete variables inserted by create_enviroment                  */
  1150. /*                                                                    */
  1151. /*    Our environment goes away when we are done executing we; just   */
  1152. /*    clean up the environment because we are freeing the storage     */
  1153. /*--------------------------------------------------------------------*/
  1154.  
  1155. static void delete_environment( char **envp )
  1156. {
  1157.    int subscript = 0;
  1158.  
  1159.    while ( envp[subscript] != NULL )
  1160.    {
  1161.       char *equal = strchr(envp[subscript]  , '=' );
  1162.       *++equal = '\0';        // Terminate the string
  1163.       if (putenv( envp[subscript] ))
  1164.       {
  1165.          printmsg(0,"Unable to reset environment \"%s\"",envp[subscript]);
  1166.          panic();
  1167.       }
  1168.       free( envp[subscript++] );
  1169.    }
  1170.  
  1171.    free( envp );
  1172. } /* delete_environment */
  1173.  
  1174.  
  1175. /*--------------------------------------------------------------------*/
  1176. /*    d o _ c o p y                                                   */
  1177. /*                                                                    */
  1178. /*    Send a file to remote node via uucp                             */
  1179. /*--------------------------------------------------------------------*/
  1180.  
  1181. static boolean do_copy(char *localfile,
  1182.                        const char *rmtsystem,
  1183.                        const char *remotefile,
  1184.                        const char *requestor,
  1185.                        const boolean success )
  1186. {
  1187.       if (rmtsystem == NULL) {
  1188.           copylocal(localfile, remotefile);
  1189.       } else {
  1190.           char    tmfile[FILENAME_MAX];  // Unix style name for c file
  1191.           char    idfile[FILENAME_MAX];  // Unix style name for data file copy
  1192.           char    work[FILENAME_MAX]; // temp area for filename hacking
  1193.           char    icfilename[FILENAME_MAX];  // our hacked c file path
  1194.           char    idfilename[FILENAME_MAX];  // our hacked d file path
  1195.  
  1196.           struct  stat    statbuf;
  1197.  
  1198.           long    int     sequence;
  1199.           static  char    subseq = 'A';
  1200.           char   *sequence_s;
  1201.           FILE   *cfile;
  1202.  
  1203.  
  1204.           sequence = getseq();
  1205.           sequence_s = JobNumber( sequence );
  1206.  
  1207.           sprintf(tmfile, spool_fmt, 'C', rmtsystem, 'Z', sequence_s);
  1208.           importpath(work, tmfile, rmtsystem);
  1209.           mkfilename(icfilename, E_spooldir, work);
  1210.  
  1211.           if (stat((char *) localfile, &statbuf) != 0)  {
  1212.               printerr( localfile );
  1213.               return FALSE;
  1214.           }
  1215.  
  1216.           sprintf(idfile , dataf_fmt, 'D', E_nodename, sequence_s,
  1217.                   (char) subseq++ );
  1218.           importpath(work, idfile, rmtsystem);
  1219.           mkfilename(idfilename, E_spooldir, work);
  1220.  
  1221.           if (!copylocal(localfile, idfilename))  {
  1222.              printmsg(0, "Copy \"%s\" to \"%s\" failed", localfile, idfilename);
  1223.              return FALSE;
  1224.           }
  1225.  
  1226.           if ((cfile = FOPEN(icfilename, "a",TEXT_MODE)) == NULL)  {
  1227.              printerr( icfilename );
  1228.              printf("cannot append to %s\n", icfilename);
  1229.              return FALSE;
  1230.           }
  1231.  
  1232.           fprintf(cfile, send_cmd, localfile, remotefile,
  1233.                    "uucp" , success ? "n" : " ", idfile,
  1234.                     success ? requestor : " ");
  1235.  
  1236.           fclose(cfile);
  1237.     };
  1238.  
  1239.     return TRUE;
  1240. } /* do_copy */
  1241.  
  1242. /*--------------------------------------------------------------------*/
  1243. /*    R e p o r t R e s u l t s                                       */
  1244. /*                                                                    */
  1245. /*    report results of command execution as specified by flags in    */
  1246. /*    X.* file.                                                       */
  1247. /*--------------------------------------------------------------------*/
  1248.  
  1249. static void ReportResults(const int status,
  1250.                           const char *input,
  1251.                                 char *output,
  1252.                           const char *command,
  1253.                           const char *job_id,
  1254.                           const time_t jtime,
  1255.                           const char *requestor,
  1256.                           const char *outnode,
  1257.                           const char *outname,
  1258.                           const boolean xflag[],
  1259.                           const char *statfil,
  1260.                           const char *machine,
  1261.                           const char *user)
  1262. {
  1263.      char address[MAXADDR];
  1264.      char subject[80];
  1265.      FILE *mailtmp = NULL;
  1266.      char *tempmail;
  1267.  
  1268.  
  1269.      if (!(xflag[X_FAILED] | xflag[X_SUCCESS] |
  1270.            xflag[X_INPUT]  | xflag[X_STATFIL]))
  1271.      {  /* default actions */
  1272.          unlink(output);
  1273.          return;
  1274.      }
  1275.  
  1276.      tempmail = mktempname(NULL, "TMP");
  1277.  
  1278.      if ((mailtmp = FOPEN(tempmail, "w+", BINARY_MODE)) == NULL) {
  1279.          printerr(tempmail);
  1280.          return;
  1281.      }
  1282.  
  1283.      sprintf(subject, "\"[uucp job %s (%s)]\"", job_id, dater(jtime, NULL) );
  1284.  
  1285.      fprintf(mailtmp,"remote execution\n");
  1286.      fprintf(mailtmp,"%s\n", command);
  1287.  
  1288. #ifdef BETA_TEST
  1289.      strcpy(address,"postmaster");
  1290. #else
  1291.      if (equal(machine, E_nodename))
  1292.         strcpy(address, requestor);
  1293.      else
  1294.         sprintf(address,"%s!%s", machine, requestor);
  1295. #endif
  1296.  
  1297.      if (xflag[E_NORMAL])
  1298.      {                        // command succeded, process appropriate flags
  1299.  
  1300.        fprintf(mailtmp,"exited normally\n");
  1301.  
  1302.        if (xflag[X_OUTPUT])
  1303.            do_copy(output, outnode, outname, requestor, xflag[X_SUCCESS]);
  1304.        else
  1305.            unlink(output);
  1306.  
  1307.        fclose(mailtmp);
  1308.  
  1309.        if (xflag[X_SUCCESS]) {
  1310.           if (xflag[X_STATFIL]) {
  1311.               do_copy(tempmail, outnode, statfil, requestor, xflag[X_SUCCESS]);
  1312.           } else {
  1313.               MailStatus(tempmail, address, subject);
  1314.           }
  1315.        };
  1316.  
  1317.    } else {            /* command failed, process appropriate flags   */
  1318.      if (xflag[E_NOACC])
  1319.          fprintf(mailtmp,"file access denied to %s!%s", machine, user);
  1320.      else if (xflag[E_NOEXE])
  1321.         fprintf(mailtmp,"execution permission denied to %s!%s\n",
  1322.                 machine, requestor);
  1323.      else if (xflag[E_SIGNAL])
  1324.         fprintf(mailtmp,"terminated by signal\n");
  1325.      else if (xflag[E_STATUS])
  1326.         fprintf(mailtmp,"exited with status %d\n", status);
  1327.      else /* xflag->e & E_FAILED */
  1328.         fprintf(mailtmp,"failed completely\n");
  1329.  
  1330.  
  1331.      if (xflag[E_STATUS]) {
  1332.        if ((xflag[X_FAILED]) && !(xflag[X_INPUT])) {
  1333.            fprintf(mailtmp,"===== error output not available =====\n");
  1334.        } else if ((xflag[X_FAILED]) && (xflag[X_INPUT])) {
  1335.            fprintf(mailtmp,"===== stdin was ");
  1336.  
  1337.            if (xflag[S_CORRUPT])
  1338.                fprintf(mailtmp,"unreadable =====\n");
  1339.            else if (xflag[S_EMPTY])
  1340.                fprintf(mailtmp,"empty =====\n");
  1341.            else if (xflag[S_NOREAD])
  1342.                fprintf(mailtmp,"denied read permission =====\n");
  1343.            else {
  1344.                fprintf(mailtmp,"=====\n");
  1345.                AppendData( input, mailtmp);
  1346.            };
  1347.            unlink(input);
  1348.  
  1349.            fprintf(mailtmp,"===== stderr is unavailable =====\n");
  1350.        }
  1351.      }
  1352.  
  1353.      fclose(mailtmp);
  1354.  
  1355.      if (xflag[X_STATFIL]) {
  1356.          do_copy(tempmail, outnode, statfil, requestor, xflag[X_SUCCESS]);
  1357.      } else {
  1358.          MailStatus(tempmail, address, subject);
  1359.      }
  1360.  
  1361.    }
  1362.  
  1363.    if (xflag[X_OUTPUT])
  1364.        unlink(output);
  1365.  
  1366.    unlink(tempmail);
  1367.    return;
  1368. } /* ReportResults */
  1369.  
  1370. /*--------------------------------------------------------------------*/
  1371. /* A p p e n d D a t a                                                */
  1372. /*                                                                    */
  1373. /* Append data to output file                                         */
  1374. /*--------------------------------------------------------------------*/
  1375.  
  1376. static boolean AppendData( const char *input, FILE* dataout)
  1377. {
  1378.    FILE    *datain;
  1379.    char     buf[BUFSIZ];
  1380.    boolean  status = TRUE;
  1381.  
  1382. /*--------------------------------------------------------------------*/
  1383. /*                      Verify the input opened                       */
  1384. /*--------------------------------------------------------------------*/
  1385.  
  1386.    if (input == NULL)
  1387.       return FALSE;
  1388.    else
  1389.       datain = FOPEN(input, "r",TEXT_MODE);
  1390.  
  1391.    if (datain == NULL) {
  1392.       printerr(input);
  1393.       printmsg(0,"Unable to open input file \"%s\"", input);
  1394.       return FALSE;
  1395.    } /* datain */
  1396.  
  1397. /*--------------------------------------------------------------------*/
  1398. /*                       Loop to copy the data                        */
  1399. /*--------------------------------------------------------------------*/
  1400.  
  1401.    while (fgets(buf, BUFSIZ, datain) != 0)
  1402.    {
  1403.       if (fputs(buf, dataout) == EOF)     // I/O error?
  1404.       {
  1405.          printmsg(0,"AppendData: I/O error on output file");
  1406.          printerr("dataout");
  1407.          fclose(datain);
  1408.          return FALSE;
  1409.       } /* if */
  1410.    } /* while */
  1411.  
  1412. /*--------------------------------------------------------------------*/
  1413. /*                      Close up shop and return                      */
  1414. /*--------------------------------------------------------------------*/
  1415.  
  1416.    if (ferror(datain))        // Clean end of file on input?
  1417.    {
  1418.       printerr(input);
  1419.       clearerr(datain);
  1420.       status = FALSE;
  1421.    }
  1422.  
  1423.    fclose(datain);
  1424.    return status;
  1425.  
  1426. } /* AppendData */
  1427.  
  1428. /*--------------------------------------------------------------------*/
  1429. /*    M a i l S t a t u s                                             */
  1430. /*                                                                    */
  1431. /*    Send text in a mailbag file to address(es) specified by line.   */
  1432. /*--------------------------------------------------------------------*/
  1433.  
  1434. static boolean MailStatus(char *tempfile,
  1435.                           char *address,
  1436.                           char *subject)
  1437. {
  1438.    boolean status;
  1439.    char **envp;
  1440.    char buf[BUFSIZ];
  1441.  
  1442. /*--------------------------------------------------------------------*/
  1443. /*                            Invoke RMAIL                            */
  1444. /*--------------------------------------------------------------------*/
  1445.  
  1446.    envp = create_environment( "uucp", NULL );
  1447.  
  1448.    strcpy(buf, "-w -f " );
  1449.    strcat(buf, tempfile );
  1450.    if ( subject != NULL )
  1451.    {
  1452.       strcat(buf, " -s " );
  1453.       strcat(buf, subject );
  1454.    }
  1455.    strcat( buf, " " );
  1456.    strcat( buf, address );
  1457.  
  1458.    status = execute( RMAIL, buf, NULL, NULL, TRUE, FALSE );
  1459.  
  1460.    delete_environment( envp );
  1461.  
  1462. /*--------------------------------------------------------------------*/
  1463. /*                       Report errors, if any                        */
  1464. /*--------------------------------------------------------------------*/
  1465.  
  1466.    if ( status < 0 )
  1467.    {
  1468.       printerr( RMAIL );
  1469.       printmsg(0,"Unable to execute rmail; status not delivered.");
  1470.    }
  1471.    else if ( status > 0 )
  1472.       printmsg(0, "Rmail returned error;\
  1473.  status delivery may be incomplete.");
  1474.  
  1475. /*--------------------------------------------------------------------*/
  1476. /*                          Return to caller                          */
  1477. /*--------------------------------------------------------------------*/
  1478.  
  1479.    return (status == 0 );
  1480.  
  1481. } /*MailStatus*/
  1482.